home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
raytrace
/
rayshade
/
graphtal.lzh
/
Graphtal.Amiga
/
TransMatrix.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-19
|
10KB
|
367 lines
/*
* TransMatrix.C - methods for general 4x3 transformation matrices.
*
* Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
* University of Berne, Switzerland
* Portions Copyright (C) 1990, Jonathan P. Leech
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
*/
#include "TransMatrix.h"
/*
* Copied from lsys by Jonathan P. Leech.
*/
void SinCos(real alpha, real& sin_a, real& cos_a)
{
const real tolerance = 1e-10;
sin_a = sin(alpha);
cos_a = cos(alpha);
if (cos_a > 1-tolerance) {
cos_a = 1; sin_a = 0;
}
else if (cos_a < -1+tolerance) {
cos_a = -1; sin_a = 0;
}
if (sin_a > 1-tolerance) {
cos_a = 0; sin_a = 1;
}
else if (sin_a < -1+tolerance) {
cos_a = 0; sin_a = -1;
}
}
//___________________________________________________________ TransMatrix
TransMatrix::TransMatrix()
{
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
m[i][j] = (i == j);
}
TransMatrix::TransMatrix(const Vector& v1, const Vector& v2,
const Vector& v3)
{
m[0][0] = v1[0]; m[0][1] = v1[1]; m[0][2] = v1[2];
m[1][0] = v2[0]; m[1][1] = v2[1]; m[1][2] = v2[2];
m[2][0] = v3[0]; m[2][1] = v3[1]; m[2][2] = v3[2];
m[3][0] = m[3][1] = m[3][2] = 0;
}
TransMatrix::TransMatrix(const Vector&v1, const Vector& v2,
const Vector& v3, const Vector& v4)
{
m[0][0] = v1[0]; m[0][1] = v1[1]; m[0][2] = v1[2];
m[1][0] = v2[0]; m[1][1] = v2[1]; m[1][2] = v2[2];
m[2][0] = v3[0]; m[2][1] = v3[1]; m[2][2] = v3[2];
m[3][0] = v4[0]; m[3][1] = v4[1]; m[3][2] = v4[2];
}
TransMatrix::TransMatrix(const TransMatrix& t)
{
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
m[i][j] = t.m[i][j];
}
const TransMatrix& TransMatrix::operator=(const TransMatrix& t)
{
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
m[i][j] = t.m[i][j];
return *this;
}
TransMatrix& TransMatrix::operator+=(const TransMatrix& t)
{
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
m[i][j] += t.m[i][j];
return *this;
}
TransMatrix& TransMatrix::operator-=(const TransMatrix& t)
{
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
m[i][j] -= t.m[i][j];
return *this;
}
TransMatrix& TransMatrix::operator*=(const TransMatrix& t)
{
TransMatrix tmp(*this);
for (register int i=0; i<3; i++) {
m[0][i] = tmp.m[0][0]*t.m[0][i] + tmp.m[0][1]*t.m[1][i] + tmp.m[0][2]*t.m[2][i];
m[1][i] = tmp.m[1][0]*t.m[0][i] + tmp.m[1][1]*t.m[1][i] + tmp.m[1][2]*t.m[2][i];
m[2][i] = tmp.m[2][0]*t.m[0][i] + tmp.m[2][1]*t.m[1][i] + tmp.m[2][2]*t.m[2][i];
m[3][i] = tmp.m[3][0]*t.m[0][i] + tmp.m[3][1]*t.m[1][i] + tmp.m[3][2]*t.m[2][i] +
t.m[3][i];
}
return *this;
}
TransMatrix TransMatrix::operator-()
{
TransMatrix result;
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
result.m[i][j] = m[i][j];
return result;
}
TransMatrix TransMatrix::operator+(const TransMatrix& t)
{
TransMatrix result;
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
result.m[i][j] = m[i][j] + t.m[i][j];
return result;
}
TransMatrix TransMatrix::operator-(const TransMatrix& t)
{
TransMatrix result;
for (register int i=0; i<4; i++)
for (register int j=0; j<3; j++)
result.m[i][j] = m[i][j] - t.m[i][j];
return result;
}
TransMatrix TransMatrix::operator*(const TransMatrix& t)
{
TransMatrix result;
for (register int i=0; i<3; i++) {
result.m[0][i] = m[0][0]*t.m[0][i] + m[0][1]*t.m[1][i] + m[0][2]*t.m[2][i];
result.m[1][i] = m[1][0]*t.m[0][i] + m[1][1]*t.m[1][i] + m[1][2]*t.m[2][i];
result.m[2][i] = m[2][0]*t.m[0][i] + m[2][1]*t.m[1][i] + m[2][2]*t.m[2][i];
result.m[3][i] = m[3][0]*t.m[0][i] + m[3][1]*t.m[1][i] + m[3][2]*t.m[2][i]
+ t.m[3][i];
}
return result;
}
/*
* Compute the inverse of a 3D affine matrix; i.e. a matrix with a dimen-
* sionality of 4 where the right column has entries (0, 0, 0, 1).
*
* This procedures treats the 4 by 4 matrix as ablock matrix and calculates
* the inverse of one submatrix for a significant performance improvement
* over a general procedure that can invert any nonsingular matrix:
* -- -- -- --
* | | -1 | -1 |
* | A 0 | | A 0 |
* -1 | | | |
* M = | | = | -1 |
* | C 1 | | -C A 1 |
* | | | |
* -- -- -- --
*
* where M is a 4 by 4 matrix,
* A is the 3 by 3 upper left submatrix of M,
* C is the 1 by 3 lower left subnatrix of M.
*
* Returned value:
* 1 matrix is nonsingular
* 0 otherwise
*
* Reference GraphicsGems I and Craig Kolbs rayshade.
*/
int TransMatrix::invert()
{
TransMatrix ttmp;
real det;
/*
* Calculate the determinant of submatrix A (optimized version:
* don,t just compute the determinant of A)
*/
ttmp.m[0][0] = m[1][1]*m[2][2] - m[1][2]*m[2][1];
ttmp.m[1][0] = m[1][0]*m[2][2] - m[1][2]*m[2][0];
ttmp.m[2][0] = m[1][0]*m[2][1] - m[1][1]*m[2][0];
ttmp.m[0][1] = m[0][1]*m[2][2] - m[0][2]*m[2][1];
ttmp.m[1][1] = m[0][0]*m[2][2] - m[0][2]*m[2][0];
ttmp.m[2][1] = m[0][0]*m[2][1] - m[0][1]*m[2][0];
ttmp.m[0][2] = m[0][1]*m[1][2] - m[0][2]*m[1][1];
ttmp.m[1][2] = m[0][0]*m[1][2] - m[0][2]*m[1][0];
ttmp.m[2][2] = m[0][0]*m[1][1] - m[0][1]*m[1][0];
det = m[0][0]*ttmp.m[0][0] - m[0][1]*ttmp.m[1][0] + m[0][2]*ttmp.m[2][0];
/*
* singular matrix ?
*/
if (fabs(det) < EPSILON*EPSILON)
return 0;
det = 1/det;
/*
* inverse(A) = adj(A)/det(A)
*/
ttmp.m[0][0] *= det;
ttmp.m[0][2] *= det;
ttmp.m[1][1] *= det;
ttmp.m[2][0] *= det;
ttmp.m[2][2] *= det;
det = -det;
ttmp.m[0][1] *= det;
ttmp.m[1][0] *= det;
ttmp.m[1][2] *= det;
ttmp.m[2][1] *= det;
ttmp.m[3][0] = -(ttmp.m[0][0]*m[3][0] + ttmp.m[1][0]*m[3][1] + ttmp.m[2][0]*m[3][2]);
ttmp.m[3][1] = -(ttmp.m[0][1]*m[3][0] + ttmp.m[1][1]*m[3][1] + ttmp.m[2][1]*m[3][2]);
ttmp.m[3][2] = -(ttmp.m[0][2]*m[3][0] + ttmp.m[1][2]*m[3][1] + ttmp.m[2][2]*m[3][2]);
*this = ttmp;
return 1;
}
/*
* Compute general rotation matrix.
* Adapted from Craig Kolbs rayshade.
*/
void TransMatrix::setRotate(const Vector& v, real alpha)
{
real sin_a, cos_a, n1, n2, n3;
Vector n(v.normalized());
SinCos(alpha, sin_a, cos_a);
n1 = n[0]; n2 = n[1]; n3 = n[2];
m[0][0] = (n1*n1 + (1. - n1*n1)*cos_a);
m[0][1] = (n1*n2*(1. - cos_a) + n3*sin_a);
m[0][2] = (n1*n3*(1. - cos_a) - n2*sin_a);
m[1][0] = (n1*n2*(1. - cos_a) - n3*sin_a);
m[1][1] = (n2*n2 + (1. - n2*n2)*cos_a);
m[1][2] = (n2*n3*(1. - cos_a) + n1*sin_a);
m[2][0] = (n1*n3*(1. - cos_a) + n2*sin_a);
m[2][1] = (n2*n3*(1. - cos_a) - n1*sin_a);
m[2][2] = (n3*n3 + (1. - n3*n3)*cos_a);
m[3][0] = m[3][1] = m[3][2] = 0;
}
TransMatrix& TransMatrix::rotate(const Vector& v, real alpha)
{
TransMatrix rot;
rot.setRotate(v, alpha);
return this->operator*=(rot);
}
TransMatrix& TransMatrix::rotate(Axis a, const real sin_a, const real cos_a)
{
static real m00, m01, m10, m11, m20, m21, m30, m31;
switch(a) {
case X:
m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; m31 = m[3][1];
m[0][1] = m01*cos_a-m[0][2]*sin_a; m[0][2] = m01*sin_a+m[0][2]*cos_a;
m[1][1] = m11*cos_a-m[1][2]*sin_a; m[1][2] = m11*sin_a+m[1][2]*cos_a;
m[2][1] = m21*cos_a-m[2][2]*sin_a; m[2][2] = m21*sin_a+m[2][2]*cos_a;
m[3][1] = m31*cos_a-m[3][2]*sin_a; m[3][2] = m31*sin_a+m[3][2]*cos_a;
break;
case Y:
m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; m30 = m[3][0];
m[0][0] = m00*cos_a-m[0][2]*sin_a; m[0][2] = m00*sin_a+m[0][2]*cos_a;
m[1][0] = m10*cos_a-m[1][2]*sin_a; m[1][2] = m10*sin_a+m[1][2]*cos_a;
m[2][0] = m20*cos_a-m[2][2]*sin_a; m[2][2] = m20*sin_a+m[2][2]*cos_a;
m[3][0] = m30*cos_a-m[3][2]*sin_a; m[3][2] = m30*sin_a+m[3][2]*cos_a;
break;
case Z:
m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; m30 = m[3][0];
m[0][0] = m00*cos_a-m[0][1]*sin_a; m[0][1] = m00*sin_a+m[0][1]*cos_a;
m[1][0] = m10*cos_a-m[1][1]*sin_a; m[1][1] = m10*sin_a+m[1][1]*cos_a;
m[2][0] = m20*cos_a-m[2][1]*sin_a; m[2][1] = m20*sin_a+m[2][1]*cos_a;
m[3][0] = m30*cos_a-m[3][1]*sin_a; m[3][1] = m30*sin_a+m[3][1]*cos_a;
break;
default:
Error(ERR_PANIC, "TransMatrix::rotate illegal value for axis");
}
return *this;
}
TransMatrix& TransMatrix::rotate(Axis a, const real alpha)
{
real sin_a, cos_a;
SinCos(alpha, sin_a, cos_a);
return this->rotate(a, sin_a, cos_a);
}
TransMatrix& TransMatrix::scale(const real Sx, const real Sy, const real Sz)
{
for (register int i=0; i<4; i++) {
m[i][0] *= Sx;
m[i][1] *= Sy;
m[i][2] *= Sz;
}
return *this;
}
TransMatrix& TransMatrix::translate(const Vector& T)
{
m[3][0] += T[0];
m[3][1] += T[1];
m[3][2] += T[2];
return *this;
}
Vector operator*(const Vector &v, const TransMatrix& t)
{
return Vector(t.m[0][0]*v[0] + t.m[1][0]*v[1] + t.m[2][0]*v[2] + t.m[3][0],
t.m[0][1]*v[0] + t.m[1][1]*v[1] + t.m[2][1]*v[2] + t.m[3][1],
t.m[0][2]*v[0] + t.m[1][2]*v[1] + t.m[2][2]*v[2] + t.m[3][2]);
}
ostream& operator<<(ostream &os, const TransMatrix& t)
{
for (register int i=0; i<4; i++) {
os << "\t( " << t.m[i][0] << ' ' << t.m[i][1] << ' ' <<t.m[i][2] << " )\n";
}
return os;
}